package org.example;

import cn.clj.*;
import cn.clj.cell.CljCell;
import org.junit.Test;

import java.util.Hashtable;
import java.util.List;

public class MyClojureEval_case {

    public static MyClojureReader getReader(String txt)
    {
        CljLinesFromString myIInput = new CljLinesFromString(txt);
        CljCharIterator myCharIterator = new CljCharIterator(myIInput);
        CljLexer lexer = new CljLexer(myCharIterator);
        MyClojureReader myLispReader = new MyClojureReader(lexer);
        return myLispReader;
    }

    @Test
    public void test_2() throws Exception {

        MyClojureInterp myClojureInterp = new MyClojureInterp();
        //MyClojureReader myLispReader = getReader("(defn my_add [x y] (+ y x))");
        //MyClojureReader myLispReader = getReader("(defn my_add ([x y z] (+ y x z)) ([x y] (+ y x)))");
        MyClojureReader myLispReader = getReader("(defn add \n" +
                "    ([a b & c] (+ a b (apply * c))) \n" +
                "    ([a b] (+ a b)))");
        CljCell myCell = myLispReader.getExpression();
        //CljResult rs = myClojureInterp.eval(myCell, new Hashtable<String, CljResult>(), new CljResult());
        myClojureInterp.eval(myCell, new Hashtable<String, CljCell>(), null, new CljCell());
        myLispReader = getReader("(add 1 2.1 2 3 4 5)");
        //myLispReader = getReader("(add 1 2.3 4 5)");
        myCell = myLispReader.getExpression();
        CljCell rs = myClojureInterp.eval(myCell, new Hashtable<String, CljCell>(), null, new CljCell());
        System.out.println(rs.getCell().toString());
    }

    @Test
    public void test_31() throws Exception {

        MyClojureInterp myClojureInterp = new MyClojureInterp();
        //MyClojureReader myLispReader = getReader("(defn my_add [x y] (+ y x))");
        //MyClojureReader myLispReader = getReader("(defn my_add ([x y z] (+ y x z)) ([x y] (+ y x)))");
        MyClojureReader myLispReader = getReader("(defn add \n" +
                "    ([a c & b] (+ a c (apply * b))) \n" +
                "    ([a [b & c]] (+ a b (apply * c))))");
        CljCell myCell = myLispReader.getExpression();
        //CljResult rs = myClojureInterp.eval(myCell, new Hashtable<String, CljResult>(), new CljResult());
        myClojureInterp.eval(myCell, new Hashtable<String, CljCell>(), null, new CljCell());
        //myLispReader = getReader("(add 1 2.3)");
        //myLispReader = getReader("(add 1 2.3 4 5)");
        //myLispReader = getReader("(add 1 '(2 3 4))");
        myLispReader = getReader("(add 1 [2 3 4])");
        myCell = myLispReader.getExpression();
        CljCell rs = myClojureInterp.eval(myCell, new Hashtable<String, CljCell>(), null, new CljCell());
        System.out.println(rs.getCell().toString());
    }

    @Test
    public void test_1() throws Exception {

        MyClojureReader myLispReader = getReader("(>= 1 2 :else 3)");
        CljCell myCell = myLispReader.getExpression();
        System.out.println(myCell.toString());
    }

    @Test
    public void test_cond() throws Exception {

//        MyClojureReader myLispReader = getReader("(cond\n" +
//                "    (< n 0) \"negative\"\n" +
//                "    (> n 0) \"positive\"\n" +
//                "    :else \"zero\")");
        MyClojureReader myLispReader = getReader("(cond\n" +
                "    (> n 0) \"positive\"\n" +
                "    :else \"zero\")");
        CljCell myCell = myLispReader.getExpression();
        List<CljCell> lst = (List<CljCell>) myCell.getCell();
        if (lst.size() > 1 && lst.size() % 2 > 0) {
            for (int i = 1; i < lst.size(); i += 2) {
                System.out.println(lst.get(i).toString() + " " + lst.get(i + 1).toString());
            }
        }
        System.out.println(lst.size());
        System.out.println((lst.size() - 1) % 2);
        System.out.println(myCell.toString());
    }

    @Test
    public void test_cond_1() throws Exception {

        MyClojureInterp myClojureInterp = new MyClojureInterp();
//        MyClojureReader myLispReader = getReader("(cond\n" +
//                "    (< n 0) \"negative\"\n" +
//                "    (> n 0) \"positive\"\n" +
//                "    :else \"zero\")");
        MyClojureReader myLispReader = getReader("(cond (> 1 5) (println 1) :else (println \"吴大富\"))");
        CljCell myCell = myLispReader.getExpression();
        CljCell cell = myClojureInterp.eval(myCell, new Hashtable<String, CljCell>(), null, new CljCell());
        System.out.println(cell.toString());
    }

    @Test
    public void test_let() throws Exception {

        MyClojureInterp myClojureInterp = new MyClojureInterp();
        MyClojureReader myLispReader = getReader("(let [a 1 b 2] \n" +
                "         (+ a b))");
        CljCell myCell = myLispReader.getExpression();

        System.out.println(myCell.toString());
        CljCell cell = myClojureInterp.eval(myCell, new Hashtable<String, CljCell>(), null, new CljCell());
        System.out.println(cell.toString());
    }

    @Test
    public void test_loop() throws Exception {

        MyClojureInterp myClojureInterp = new MyClojureInterp();
        MyClojureReader myLispReader = getReader("(loop [iter 1\n" +
                "       acc  0]\n" +
                "  (if (> iter 10)\n" +
                "    (println acc)\n" +
                "    (recur (+ 1 iter) (+ acc iter))))");
        CljCell myCell = myLispReader.getExpression();
        //System.out.println(myCell.toString());
        myClojureInterp.eval(myCell, new Hashtable<String, CljCell>(), null, new CljCell());
    }

    @Test
    public void test_recure7() throws Exception {

        MyClojureInterp myClojureInterp = new MyClojureInterp();
        MyClojureReader myLispReader = getReader("(println \"吴大富\")");
        CljCell myCell = myLispReader.getExpression();
        //CljResult rs = myClojureInterp.eval(myCell, new Hashtable<String, CljResult>(), new CljResult());
        myClojureInterp.eval(myCell, new Hashtable<String, CljCell>(), null, new CljCell());

    }

    @Test
    public void test_recure() throws Exception {

        MyClojureInterp myClojureInterp = new MyClojureInterp();
        //MyClojureReader myLispReader = getReader("(defn my_add [x y] (+ y x))");
        //MyClojureReader myLispReader = getReader("(defn my_add ([x y z] (+ y x z)) ([x y] (+ y x)))");
        MyClojureReader myLispReader = getReader("(defn my [[f & r]]\n" +
                "    (if (not (nil? f))\n" +
                "        (do (+ f 1)\n" +
                "            (recur r))))");
        CljCell myCell = myLispReader.getExpression();
        //CljResult rs = myClojureInterp.eval(myCell, new Hashtable<String, CljResult>(), new CljResult());
        myClojureInterp.eval(myCell, new Hashtable<String, CljCell>(), null, new CljCell());
        myLispReader = getReader("(my [1 2])");
        //myLispReader = getReader("(add 1 2.3 4 5)");
        myCell = myLispReader.getExpression();
        CljCell rs = myClojureInterp.eval(myCell, new Hashtable<String, CljCell>(), null, new CljCell());
        if (rs.getCell() != null) {
            System.out.println(rs.getCell().toString());
        }
    }

    @Test
    public void test_recur1() throws Exception {

        MyClojureInterp myClojureInterp = new MyClojureInterp();
        //MyClojureReader myLispReader = getReader("(defn my_add [x y] (+ y x))");
        //MyClojureReader myLispReader = getReader("(defn my_add ([x y z] (+ y x z)) ([x y] (+ y x)))");
        MyClojureReader myLispReader = getReader("(defn my [[f & r]]\n" +
                "    (if false\n" +
                "        (do (+ f 1)\n" +
                "            (recur r))))");
        CljCell myCell = myLispReader.getExpression();
        //CljResult rs = myClojureInterp.eval(myCell, new Hashtable<String, CljResult>(), new CljResult());
        myClojureInterp.eval(myCell, new Hashtable<String, CljCell>(), null, new CljCell());
        myLispReader = getReader("(my [1 2])");
        //myLispReader = getReader("(add 1 2.3 4 5)");
        myCell = myLispReader.getExpression();
        CljCell rs = myClojureInterp.eval(myCell, new Hashtable<String, CljCell>(), null, new CljCell());
        System.out.println(rs.getCell().toString());
    }

    @Test
    public void test_and() throws Exception {

        //MyClojureReader myLispReader = getReader("(and (> 3 1) (< 1 5))");
        MyClojureReader myLispReader = getReader("(nil? f)");
        CljCell myCell = myLispReader.getExpression();

        System.out.println(myCell.toString());
    }

}































